/**
 * @file STL_REGEX.h
 * @author Derek Liu (yjkhtddx@sina.com)
 * @brief 
 * @version 0.1
 * @date 2021-01-08
 * 
 * @copyright Copyright Sci-Tech Laboratories (c) 2021
 * 
 */

#ifndef __STL_REGEX_H__
#define __STL_REGEX_H__

#include <string>
#include <regex>
#include <iostream>
#include "STLOG.h"

namespace STL
{
    class STL_REGEX
    {
    public:
        // //域名：
        // static std::regex regDomain("[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?");
        // //InternetURL：
        // static std::regex regUrl("^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$");
        // //Email地址：
        // static std::regex regEmail("^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$");
        // //电话号码(“XXX-XXXXXXX”、”XXXX-XXXXXXXX”、”XXX-XXXXXXX”、”XXX-XXXXXXXX”、”XXXXXXX”和”XXXXXXXX)：
        // static std::regex regPhone("^($$\d{3,4}-)|\d{3.4}-)?\d{7,8}$");
        // //国内电话号码(0511-4405222、021-87888822)：
        // static std::regex regTel("\d{3}-\d{8}|\d{4}-\d{7}");
        // //身份证号(15位、18位数字)：
        // static std::regex regID("^\d{15}|\d{18}$");
        // //短身份证号码(数字、字母x结尾)：
        // static std::regex regID2("^([0-9]){7,18}(x|X)?$ 或 ^\d{8,18}|[0-9x]{8,18}|[0-9X]{8,18}?$");
        // //帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线)：
        // static std::regex regAccount("^[a-zA-Z][a-zA-Z0-9_]{4,15}$");
        // //密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线)：
        // static std::regex regPassword("^[a-zA-Z]\w{5,17}$");
        // //强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间)：
        // static std::regex regPassword2("^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$");
        // //日期格式：
        // static std::regex regDate("^\d{4}-\d{1,2}-\d{1,2}");
        // //一年的12个月(01～09和1～12)：
        // static std::regex regMonth("^(0?[1-9]|1[0-2])$");
        // //一个月的31天(01～09和1～31)：
        // static std::regex regDay("^((0?[1-9])|((1|2)[0-9])|30|31)$");
        //IPv4地址
        // static std::regex regIPv4("^((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})(\\.((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})){3}$");
        // //Port端口 0 - 65535
        // static std::regex regPort("^([0-9]|[1-9]\\d{1,3}|[1-5]\\d{4}|6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5])$");
        // //国标SSRC
        // static std::regex regGbSsrc("^\\d{10}$");
    public:
        static std::string getRtspResStatusCode(std::string res)
        {
            //RTSP/1.0 401 Unauthorized
            std::string ret = "";
            // std::regex reg_temp("RTSP/1.0 (\d+) \s+\\r\\n");
            std::regex reg_temp("(RTSP/[\\d]{1}\\.[\\d]{1}) (\\d+) (\\S+)\\r\\n");
            std::smatch sm;
            // same as :
            // std::match_results<std::string::const_iterator> sm;
            if (std::regex_search(res, sm, reg_temp))
            {
                std::cout << "-----------------------------" << std::endl;
                for (auto x : sm)
                    std::cout << x << std::endl;
                std::cout << "-----------------------------" << std::endl;
                ret = sm[2].str();
            }
            return ret;
        }

        static std::string getRtspResVersion(std::string res)
        {
            //RTSP/1.0 401 Unauthorized
            std::string ret = "";
            // std::regex reg_temp("RTSP/1.0 (\d+) \s+\\r\\n");
            std::regex reg_temp("(RTSP/[\\d]{1}\\.[\\d]{1}) (\\d+) (\\S+)\\r\\n");
            std::smatch sm;
            // same as :
            // std::match_results<std::string::const_iterator> sm;
            if (std::regex_search(res, sm, reg_temp))
            {
                std::cout << "-----------------------------" << std::endl;
                for (auto x : sm)
                    std::cout << x << std::endl;
                std::cout << "-----------------------------" << std::endl;
                ret = sm[1].str();
            }
            return ret;
        }

        static std::string getRtspResPhrase(std::string res)
        {
            //RTSP/1.0 401 Unauthorized
            std::string ret = "";
            // std::regex reg_temp("RTSP/1.0 (\d+) \s+\\r\\n");
            std::regex reg_temp("(RTSP/[\\d]{1}\\.[\\d]{1}) (\\d+) (\\S+)\\r\\n");
            std::smatch sm;
            // same as :
            // std::match_results<std::string::const_iterator> sm;
            if (std::regex_search(res, sm, reg_temp))
            {
                std::cout << "-----------------------------" << std::endl;
                for (auto x : sm)
                    std::cout << x << std::endl;
                std::cout << "-----------------------------" << std::endl;
                ret = sm[3].str();
            }
            return ret;
        }

        static std::string getRtspResWWWAuthenticateType(std::string res)
        {
            //WWW-Authenticate: Basic realm="c056e3f5d007"
            //WWW-Authenticate: Digest realm="IP Camera(D2290)", nonce="0aea84c95605f8c03ed98d1c50b74eda", stale="FALSE"

            std::regex reg_temp("WWW-Authenticate: (Basic)(Digest) \\r\\n");
        }

        static std::string getRtspResWWWAuthenticate(std::string res)
        {
            //WWW-Authenticate: Basic realm="c056e3f5d007"
            std::string ret = "";
            std::regex reg_temp("WWW-Authenticate: (\\S+)\\r\\n");
            std::smatch sm;
            // same as :
            // std::match_results<std::string::const_iterator> sm;
            if (std::regex_search(res, sm, reg_temp))
            {
                // std::cout << "-----------------------------" << std::endl;
                // for (auto x : sm)
                //     std::cout << x << std::endl;
                // std::cout << "-----------------------------" << std::endl;
                ret = sm[1].str();
            }
            return ret;
        }

    public:
        static bool isGBDeviceID(std::string deviceId)
        {
            static std::regex regGB28181DeviceID("^\\d{20}$");
            return std::regex_match(deviceId, regGB28181DeviceID);
        }
        static bool isGBDeviceIDAndLen20(std::string deviceId)
        {
            static std::regex regGB28181DeviceID("^\\d{20}$");
            return std::regex_match(deviceId, regGB28181DeviceID);
        }
        static bool isGbDomain(std::string domain)
        {
            static std::regex regGbDomain("^\\d{10}$");
            return std::regex_match(domain, regGbDomain);
        };
        static bool isGbSsrc(std::string ssrc)
        {
            static std::regex regGbSsrc("^\\d{10}$");
            return std::regex_match(ssrc, regGbSsrc);
        };

    public:
        static bool isVersion(std::string str)
        {
            static std::regex regVersion("(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})");
            return std::regex_match(str, regVersion);
        }
        static std::string getVersion(std::string str)
        {
            std::string ret = "";
            std::smatch sm;
            static std::regex regVersion("(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})");
            if (std::regex_search(str, sm, regVersion))
            {
                // stlog_debug("-----------------------------");
                // for (int i = 0; i < sm.size(); i++)
                // {
                //     stlog_debug("%s", sm[i].str().c_str());
                // }
                // stlog_debug("-----------------------------");
                ret = sm[1].str();
            }
            return ret;
        }

    public:
        static bool isIPv4(std::string ip)
        {
            static std::regex regIPv4("^((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})(\\.((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})){3}$");
            return std::regex_match(ip, regIPv4);
        };
        typedef enum PortType_e
        {
            PortType_correct, // 1 - 65535
            PortType_system,  // 1 - 1023
            PortType_custom   // 1024 - 65535
        } PortType;
        static bool isPort(std::string port)
        {
            static std::regex regPort("^([0-9]|[1-9]\\d{1,3}|[1-5]\\d{4}|6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5])$");
            return std::regex_match(port, regPort);
        };
        static bool isPort(uint16_t port, STL_REGEX::PortType type = STL_REGEX::PortType::PortType_correct)
        {
            switch (type)
            {
            case STL_REGEX::PortType::PortType_correct:
                return (port >= 1 && port <= 65535);
            case STL_REGEX::PortType::PortType_system:
                return (port >= 1 && port <= 1023);
            case STL_REGEX::PortType::PortType_custom:
                return (port >= 1024 && port <= 65535);
            default:
                return false;
            }
        };
    };

} // namespace STL

#endif /* __STL_REGEX_H__ */
